//
//  ACNetworkManager.m
//  ACFramework
//
//  Created by caoyq on 2018/11/12.
//

#import "ACNetworkManager.h"
#import "ACMacro.h"
#import "NSObject+ACExt.h"
//3rd
#import <AFNetworking/AFNetworking.h>
#import <AFNetworking/AFNetworkActivityIndicatorManager.h>

AFNetworkReachabilityManager *reachabilityManager;

@interface ACNetworkManager()

/** post与get对应的mgr */
@property (nonatomic, strong) AFHTTPSessionManager *normalManager;
/** upload与download对应的mgr */
@property (nonatomic, strong) AFHTTPSessionManager *uploadManager;
/** 存放所有需要自动取消的请求 */
@property (nonatomic, strong) NSMutableDictionary *needAutoCancelRequestList;

@end

@implementation ACNetworkManager

+ (instancetype)manager
{
    static ACNetworkManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
        reachabilityManager = [AFNetworkReachabilityManager manager];
        [reachabilityManager startMonitoring];
    });
    return instance;
}

#pragma mark - getter

- (AFHTTPSessionManager *)normalManager
{
    if (!_normalManager) {
        //状态栏开始转圈，网速慢的时候出现(暂时不用这个，每个网络请求都会有，直接掉系统的方法)
        [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
        _normalManager = [AFHTTPSessionManager manager];
        _normalManager.operationQueue.maxConcurrentOperationCount = 5;
        
        _normalManager.requestSerializer.timeoutInterval = 25;
        // AFJSONRequestSerializer 传入的数据转化为json格式，AFHTTPRequestSerializer则不会自动转化
        _normalManager.requestSerializer = [AFHTTPRequestSerializer serializer];
        _normalManager.responseSerializer = [AFHTTPResponseSerializer serializer];
        
        [_normalManager.requestSerializer setValue:@"application/json; encoding=utf-8" forHTTPHeaderField:@"Content-Type"];
        _normalManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",
                                                                    @"text/json",
                                                                    @"text/javascript",
                                                                    @"text/html",
                                                                    @"text/plain",
                                                                    @"application/atom+xml",
                                                                    @"application/xml",
                                                                    @"text/xml",
                                                                    nil];
    }
    return _normalManager;
}

- (AFHTTPSessionManager *)uploadManager
{
    if (!_uploadManager) {
        
        [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
        _uploadManager = [AFHTTPSessionManager manager];
        _uploadManager.operationQueue.maxConcurrentOperationCount = 3;
        _uploadManager.requestSerializer.timeoutInterval = 15;
        
        //这里都用AFHTTP类型，则不会主动进行json格式转化
        _uploadManager.requestSerializer = [AFHTTPRequestSerializer serializer];
        _uploadManager.responseSerializer = [AFHTTPResponseSerializer serializer];
        
        [_uploadManager.requestSerializer setValue:@"application/json; encoding=utf-8" forHTTPHeaderField:@"Content-Type"];
        _uploadManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",
                                                                    @"text/json",
                                                                    @"text/javascript",
                                                                    @"text/html",
                                                                    @"text/plain",
                                                                    @"application/atom+xml",
                                                                    @"application/xml",
                                                                    @"text/xml",
                                                                    nil];
    }
    return _uploadManager;
}


- (NSMutableDictionary *)needAutoCancelRequestList
{
    if (!_needAutoCancelRequestList) {
        _needAutoCancelRequestList = [NSMutableDictionary dictionary];
    }
    return _needAutoCancelRequestList;
}


#pragma mark - 请求关键处理

+ (NSURLSessionTask *)sendTaskWithRequest: (ACRequestBody *)requestBody
{
    if (!reachabilityManager.isReachable && reachabilityManager) {  //已开启网络检测 && 没网
        
        if (requestBody.failureBlock) {
            NSError *error = [[NSError alloc] initWithDomain:@"nonetwork" code:-1 userInfo:@{@"message": @"网络连接失败，请检查网络"}];
            requestBody.failureBlock(error);
        }
        return nil;
    }
    
    //没办法之举，NSLog打印枚举得到的都是数字，不能显示原值，所以只有手动枚举一下了
    NSString *methodString = @"";
    switch (requestBody.methodType) {
        case ACMethodTypeGet:
            methodString = @"ACMethodTypeGet";
            break;
        case ACMethodTypePost:
            methodString = @"ACMethodTypePost";
            break;
        case ACMethodTypeUpload:
            methodString = @"ACMethodTypeUpload";
            break;
        case ACMethodTypeDownload:
            methodString = @"ACMethodTypeDownload";
            break;
    }
    ACLog(@"\n开始请求：\nURL:\t%@\nMethod:\t%@\nParams:\t%@",requestBody.url,methodString,[requestBody.parameters ac_jsonPrettyStringEncoded]);
    
    //请求成功的处理
    void(^success)(NSURLSessionDataTask *,id) = ^(NSURLSessionDataTask *task, id responseObject){
        
        [self removeTask:task requestBody:requestBody];
        //不是NSData类型，则默认不需要进行json解析
        if ([responseObject isKindOfClass:[NSData class]]) {
            responseObject = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableContainers error:nil];
        }
        if (requestBody.successBlock) {
            requestBody.successBlock(responseObject);
        }
        
        ACLog(@"\n收到响应：%zd\n接口名：%@\n返回值：%@\n请求参数：%@",((NSHTTPURLResponse *)task.response).statusCode, requestBody.url, [responseObject ac_jsonPrettyStringEncoded], [requestBody.parameters ac_jsonPrettyStringEncoded]);
    };
    
    void(^failure)(NSURLSessionDataTask *, NSError *) = ^(NSURLSessionDataTask *task, NSError *error) {
        
        NSInteger errorCode = [(NSHTTPURLResponse*)task.response statusCode];
        ACLog(@"\n收到失败的响应：%ld\n %@\n请求接口：%@,请求参数：%@",(long)errorCode, error.localizedDescription, requestBody.url, [requestBody.parameters ac_jsonPrettyStringEncoded]);
        
        [self removeTask:task requestBody:requestBody];
        if (requestBody.failureBlock) {
            requestBody.failureBlock(error);
        }
    };
    
    AFHTTPSessionManager *manager = nil;
    NSURLSessionTask *task = nil;
    NSString *url = requestBody.url;
    NSDictionary *parameters = requestBody.parameters;
    
    switch (requestBody.methodType) {
        case ACMethodTypeUpload:
        case ACMethodTypeDownload:
            manager = [ACNetworkManager manager].uploadManager;
            break;
        default:
            manager = [ACNetworkManager manager].normalManager;
            break;
    }
    
    //默认c初始化的mgr都不会转化为json格式发送
    if (requestBody.requestType == ACRequestTypeJSON) {
        manager.requestSerializer = [AFJSONRequestSerializer serializer];
    }
    
    [requestBody.allHeaderFields enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        [manager.requestSerializer setValue:obj forHTTPHeaderField:key];
    }];
    
    switch (requestBody.methodType) {
        case ACMethodTypePost:
            task = [manager POST:url parameters:parameters progress:nil success:success failure:failure];
            break;
        case ACMethodTypeGet:
            task = [manager GET:url parameters:parameters progress:nil success:success failure:failure];
            break;
        case ACMethodTypeUpload:
        {
            task = [manager POST:url parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
                //fromData拼接数据
                if (requestBody.fileData) {
                    [formData appendPartWithFileData:requestBody.fileData name:@"file" fileName:requestBody.fileName mimeType:requestBody.mimeType];
                }else if (requestBody.fileURL) {
                    [formData appendPartWithFileURL:requestBody.fileURL name:@"file" fileName:requestBody.fileName mimeType:requestBody.mimeType error:nil];
                }
            } progress:^(NSProgress * _Nonnull uploadProgress) {
                if (requestBody.uploadProgressBlock) {
                    requestBody.uploadProgressBlock(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount);
                }
            } success:success failure:failure];
        }
            break;
        case ACMethodTypeDownload:
        {
            task = [manager downloadTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]] progress:^(NSProgress * _Nonnull downloadProgress) {
                
                if (requestBody.downloadProgressBlock) {
                    requestBody.downloadProgressBlock(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount);
                }
                
            } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
                
                return [NSURL fileURLWithPath:[requestBody.fileSavePath stringByAppendingPathComponent:response.suggestedFilename]];
                
            } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
                //目前下载完成并没有从 needAutoCancelRequestList 中删除对应的task，由于一般下载任务都不会自动取消，所以暂时不考虑
                if (error) {
                    !requestBody.failureBlock ?  : requestBody.failureBlock(error);
                }else {
                    !requestBody.successBlock ?  : requestBody.successBlock(nil);
                }
            }];
            [task resume];
        }
            break;
    }
    
    [self saveTask:task requestBody:requestBody];
    
    return task;
}

#pragma mark - 管理请求

///保存task
+ (void)saveTask: (NSURLSessionTask *)task requestBody: (ACRequestBody *)requestBody
{
    //状态栏显示转圈
    if (![UIApplication sharedApplication].networkActivityIndicatorVisible) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    }
    if (requestBody.isAutoCancelRequest && requestBody.requestVCName && task) {
        NSMutableDictionary *dic = [ACNetworkManager manager].needAutoCancelRequestList;
        NSMutableSet *set = dic[requestBody.requestVCName];
        if (!set) {
            set = [NSMutableSet set];
            dic[requestBody.requestVCName] = set;
        }
        [set addObject:task];
    }
}

///移除task
+ (void)removeTask: (NSURLSessionTask *)task requestBody: (ACRequestBody *)requestBody
{
    if (requestBody.isAutoCancelRequest && requestBody.requestVCName && task) {
        NSMutableDictionary *dic = [ACNetworkManager manager].needAutoCancelRequestList;
        NSMutableSet *set = dic[requestBody.requestVCName];
        if (set) {
            if ([set containsObject:task]) {
                [set removeObject:task];
            }
        }
        if (set.count == 0) {
            [dic removeObjectForKey:requestBody.requestVCName];
            //状态栏关闭转圈（只关心当前控制器中的Indicator，不再此页面不去处理Indicator）
            if ([UIApplication sharedApplication].networkActivityIndicatorVisible) {
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
            }
        }
    }
}

///停止 控制器中所有需要取消的请求
+ (void)stopAllNeedAutoCancelRequestWithVCName: (NSString *)vcName
{
    @synchronized (self) {
        //状态栏关闭转圈
        if ([UIApplication sharedApplication].networkActivityIndicatorVisible) {
            [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        }
        NSMutableDictionary *dic = [ACNetworkManager manager].needAutoCancelRequestList;
        NSMutableSet *set = dic[vcName];
        if (set) {
            [set enumerateObjectsUsingBlock:^(NSURLSessionTask *task, BOOL * _Nonnull stop) {
                [task cancel];
            }];
            [dic removeObjectForKey:vcName];
        }
    }
}

@end
